package com.dd.admin.controller.system;

import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.stp.StpUtil;
import com.dd.common.convert.SysUserConvert;
import com.dd.common.dto.system.user.SysUserCreateDTO;
import com.dd.common.dto.system.user.SysUserQueryDTO;
import com.dd.common.dto.system.user.SysUserSelfUpdateDTO;
import com.dd.common.dto.system.user.SysUserUpdateDTO;
import com.dd.common.entity.SysUser;
import com.dd.common.enums.ErrorEnum;
import com.dd.common.exception.BusinessException;
import com.dd.common.pojo.dto.IdDTO;
import com.dd.common.pojo.dto.PageDTO;
import com.dd.common.service.SysUserService;
import com.dd.common.utils.AjaxResult;
import com.dd.common.utils.PageResult;
import com.dd.common.utils.StrGenerator;
import com.dd.common.validator.annotation.IDMust;
import com.dd.common.vo.SysUserAuthInfoVO;
import com.dd.common.vo.SysUserDetailVO;
import com.dd.common.vo.SysUserVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.Map;

// 不遵守Restful规范，在URL加动词，是为了日后可以方便的迁移到只允许Get、Post请求的系统
@Slf4j
@Validated
@SaIgnore
@Tag(name = "系统用户管理", description = "系统用户管理接口")
@RestController
@RequestMapping("/sys/user")
public class SysUserController {

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private SysUserConvert sysUserConvert;

    @Operation(summary = "管理员新增", requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
            description = "管理员数据",
            required = true,
            content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = SysUserCreateDTO.class)
            )
    ))
    @PostMapping("/add")
    public AjaxResult<Boolean> add(@Validated @RequestBody SysUserCreateDTO dto) {
        dto.setPassword(StrGenerator.makeMd5(dto.getPassword()));
        return AjaxResult.success(sysUserService.save(sysUserConvert.dtoToEntity(dto)));
    }

    @Operation(summary = "管理员列表", description = "不分页查询所有管理员信息")
    @GetMapping("/list")
    public AjaxResult<Object> list(@Validated SysUserQueryDTO dto) {
        return AjaxResult.success(sysUserService.listQuery(dto));
    }

    @Operation(summary = "管理员分页列表", description = "分页查询管理员信息")
    @GetMapping("/page")
    public AjaxResult<PageResult<SysUserVO>> page(@Validated PageDTO pageDTO, @Validated SysUserQueryDTO dto) {
        return AjaxResult.success(sysUserService.pageQuery(pageDTO, dto));
    }

    @Operation(summary = "管理员详情", parameters = @Parameter(name = "id", in = ParameterIn.PATH, description = "管理员ID"))
    @GetMapping("/detail/{id}")
    public AjaxResult<SysUserDetailVO> detail(@PathVariable @IDMust Long id) {
        return AjaxResult.success(sysUserService.detail(id));
    }

    @Operation(summary = "管理员编辑", requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
            description = "管理员数据",
            content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = SysUserUpdateDTO.class))
    ))
    @PatchMapping("/edit")
    public AjaxResult<Boolean> edit(@Validated @RequestBody SysUserUpdateDTO dto) {
        return AjaxResult.success(sysUserService.edit(dto));
    }

    @Operation(summary = "管理员删除", parameters = @Parameter(name = "id", in = ParameterIn.PATH, description = "管理员ID"))
    @DeleteMapping("/delete/{id}")
    public AjaxResult<Boolean> delete(@PathVariable @IDMust Long id) {
        return AjaxResult.success(sysUserService.removeById(id));
    }

    @Operation(summary = "管理员权限信息", description = "权限信息包括：角色权限roles、菜单权限menus、按钮权限perms")
    @GetMapping("/auth/info")
    public AjaxResult<SysUserAuthInfoVO> authInfo(@Validated IdDTO idDTO) {
        return AjaxResult.success(sysUserService.getSysUserAuthInfo(idDTO.getId()));
    }

    @Operation(summary = "当前管理员更新", description = "当前管理员更新自己的个人信息", requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
            description = "自身数据",
            content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = SysUserSelfUpdateDTO.class))
    ))
    @PatchMapping("/self/update")
    public AjaxResult<Boolean> selfUpdate(@Validated @RequestBody SysUserSelfUpdateDTO dto) {
        SysUser sysUser = sysUserConvert.dtoToEntity(dto);
        sysUser.setId(StpUtil.getLoginIdAsLong());
        return AjaxResult.success(sysUserService.updateById(sysUser));
    }

    /**
     * 使用 PATCH/POST 方法更新单个字段（如 status）时，是否一定要为一个字段专门创建一个 DTO？
     * 使用 Map<String, Object> 简便接收。
     * 它的特点是：适用于动态更新任意字段，尤其是只改 1~2 个字段的场景。
     * 也正因为 Map 允许任意字段，所以缺点就是要自己提取字段，并且做安全校验
     *
     * @param map 接收字段
     * @return 响应结果
     */
    @Operation(summary = "管理员状态", description = "管理员状态切换", parameters = @Parameter(name = "id", in = ParameterIn.PATH, description = "管理员ID"))
    @PatchMapping("/status/{id}")
    public AjaxResult<Boolean> status(@PathVariable @IDMust Long id,
                                      @Validated @RequestBody Map<String, Object> map) {
        if (!map.containsKey("status")) {
            throw new BusinessException(ErrorEnum.PARAMS_MISSING, "缺少参数 status");
        }
        int status;
        try {
            status = Integer.parseInt(map.get("status").toString());
        } catch (Exception e) {
            throw new BusinessException(ErrorEnum.PARAMS_VALID_ERROR, "参数 status 错误");
        }
        if (status != 0 && status != 1) {
            throw new BusinessException(ErrorEnum.PARAMS_VALID_ERROR, "参数 status 错误");
        }
        SysUser sysUser = new SysUser();
        sysUser.setId(id);
        sysUser.setStatus(status);
        return AjaxResult.success(sysUserService.updateById(sysUser));
    }
}
